/*
 * @features: 控制碎片的生成
 * @description: 说明
 * @Date: 2021-02-10 22:56:56
 * @Author: judu233(769471424@qq.com)
 * @LastEditTime: 2021-02-16 22:22:03
 * @LastEditors: judu233
 */

const { ccclass, property } = cc._decorator;

/**碎片类型 */
enum E_PiecePosType {
    left_up = `left_up`,
    right_up = `right_up`,
    right_down = `right_down`,
    left_down = `left_down`,

    upA = `upA`,
    upB = `upB`,
    downA = `downA`,
    downB = `downB`,

    rightA = `rightA`,
    rightB = `rightB`,
    leftA = `leftA`,
    leftB = `leftB`,

    centerA = `centerA`,
    centerB = `centerB`,
}

@ccclass(`blockPiece`)
class BlockPiece {
    @property(cc.SpriteFrame)
    a: cc.SpriteFrame = null;

    @property(cc.SpriteFrame)
    b: cc.SpriteFrame = null;
}

@ccclass(`PieceSfBlock`)
class PieceSfBlock {
    @property(cc.SpriteFrame)
    public left_up: cc.SpriteFrame = null;

    @property(cc.SpriteFrame)
    public right_up: cc.SpriteFrame = null;

    @property(cc.SpriteFrame)
    public left_down: cc.SpriteFrame = null;

    @property(cc.SpriteFrame)
    public right_down: cc.SpriteFrame = null;

    @property(BlockPiece)
    public up: BlockPiece = new BlockPiece();

    @property(BlockPiece)
    public down: BlockPiece = new BlockPiece();

    @property(BlockPiece)
    public left: BlockPiece = new BlockPiece();

    @property(BlockPiece)
    public right: BlockPiece = new BlockPiece();

    @property(BlockPiece)
    public center: BlockPiece = new BlockPiece();
}

/**碎片的信息 */
interface I_PieceInfo {
    /**碎片所属的行 */
    row: number;
    /**碎片所属的列 */
    col: number;
    /**碎片的位置类型 */
    posType: E_PiecePosType;
    /**图片 */
    contentSf: cc.SpriteFrame;
    /**图片大小 */
    contentSfSize: cc.Size;

    /**mask */
    maskSf: cc.SpriteFrame;
    /**mask大小 */
    maskSfSize: cc.Size;
    /**碎片开始的位置 */
    maskStartPos: cc.Vec3;
    /**碎片的偏移 */
    maskOffset: cc.Vec3;
}

@ccclass
export default class PieceMgr extends cc.Component {
    @property({
        displayName: `碎片朝向顺时针`,
        tooltip: `第一块碎片的右边是否突出`
    })
    public isClockwise = true;

    @property({
        displayName: `碎片图片`,
        type: PieceSfBlock
    })
    public pieceList: PieceSfBlock = new PieceSfBlock();

    @property({
        displayName: `显示的图片`,
        type: cc.SpriteFrame
    })
    public contentSf: cc.SpriteFrame = null;

    /**碎片的倍数最小为4x4 => 0x0, 6x6 => 1x1*/
    @property({
        displayName: `碎片分割倍数`,
    })
    public multipleSize = cc.size(2, 2);

    @property({
        displayName: `自定义缩放`,
        tooltip: `是否自定义显示图片的缩放尺寸`
    })
    public customizeScaleSize = true;

    /**拼图容器的大小 */
    @property({
        displayName: `自定义大小`,
        visible: function (this: PieceMgr) { return this.customizeScaleSize; }
    })
    public bgSize = cc.size(500, 500);

    @property({
        displayName: `等比缩放`,
        tooltip: `原图像等比缩放`,
        visible: function (this: PieceMgr) { return !this.customizeScaleSize; }
    })
    public scaleMagnification = 1;

    /**格子的实际行数和列数 */
    private gradCell = cc.size(0, 0);

    /**碎片去掉凸出部分的宽高的方形原始尺寸 */
    private pieceOriginaWidth = 0;
    private pieceOriginaHeight = 0;

    /**碎片总偏移尺寸 */
    private pieceOffset = 34;
    /**碎片空白地方偏移尺寸 */
    private blankOffset = 17;

    /**图片缩放的比例 */
    private contentScalingRatio = cc.v2(1, 1);
    /**mask缩放比例 */
    private maskScalingRatio = cc.v2(1, 1);

    /**碎片map */
    private pieceMap: Map<string, cc.Node> = new Map();

    /**是否显示完整的背景 */
    private isTestShow = true;

    onLoad() {
        var manager = cc.director.getCollisionManager();
        manager.enabled = true;
        manager.enabledDebugDraw = true;
        manager.enabledDrawBoundingBox = true;
    }

    start() {
        this.generatePieceList(4, 4, (info, piece) => {
            cc.log(info);
            let boxCollider = piece.addComponent(cc.BoxCollider);
            let size = boxCollider.size = piece.getContentSize();
            boxCollider.offset = cc.v2(size.width / 2, -size.height / 2);
            this.node.addChild(piece);
            piece.opacity = 250;
        });
    }


    /**
     * 生成一个二维碎片列表  168-34=134
     * @param row 行
     * @param col 列
     * @param callFun 每生成一个调用一次
     */
    public generatePieceList(row = 4, col = 4, callFun: (info: I_PieceInfo, piece: cc.Node) => void) {
        //计算实际行列
        let addRow = Math.floor(this.multipleSize.width);
        let addCol = Math.floor(this.multipleSize.height);
        addRow = addRow < 0 ? 0 : addRow;
        addCol = addCol < 0 ? 0 : addCol;
        row = (row >= 4 ? row : 4) + addRow * 2;
        col = (col >= 4 ? col : 4) + addCol * 2;
        this.gradCell = cc.size(row, col);
        let contentSize = this.contentSf.getOriginalSize();

        //设置目标尺寸
        this.bgSize = this.customizeScaleSize ? this.bgSize :
            cc.size(contentSize.width * this.scaleMagnification, contentSize.height * this.scaleMagnification);
        //计算图片缩放比例
        this.contentScalingRatio.x = this.customizeScaleSize ? this.bgSize.width / contentSize.width : this.scaleMagnification;
        this.contentScalingRatio.y = this.customizeScaleSize ? this.bgSize.height / contentSize.height : this.scaleMagnification;
        //碎片目标大小
        let w = this.gradCell.width;
        let h = this.gradCell.height;
        // debugger;
        this.pieceOriginaWidth = (this.bgSize.width + 2 * w * (this.pieceOffset)) / w;
        this.pieceOriginaHeight = (this.bgSize.height + 2 * h * (this.pieceOffset)) / h;
        //生成
        let pieceList: [cc.Node, I_PieceInfo][][] = [];
        for (let i = 0; i < row; i++) {
            pieceList[i] = [];
            for (let j = 0; j < col; j++) {
                let pieceInfo = this.getPieceInfo(j, i);
                if (
                    !
                    (
                        pieceInfo.posType == E_PiecePosType.left_down
                        ||
                        pieceInfo.posType == E_PiecePosType.left_up ||
                        pieceInfo.posType == E_PiecePosType.right_up ||
                        pieceInfo.posType == E_PiecePosType.right_down ||
                        pieceInfo.posType == E_PiecePosType.leftA ||
                        pieceInfo.posType == E_PiecePosType.leftB
                        ||
                        pieceInfo.posType == E_PiecePosType.rightA ||
                        pieceInfo.posType == E_PiecePosType.rightB
                        ||
                        pieceInfo.posType == E_PiecePosType.upA ||
                        pieceInfo.posType == E_PiecePosType.upB
                        ||
                        pieceInfo.posType == E_PiecePosType.downA ||
                        pieceInfo.posType == E_PiecePosType.downB
                        ||
                        pieceInfo.posType == E_PiecePosType.centerA
                        ||
                        pieceInfo.posType == E_PiecePosType.centerB
                    )) continue;
                let pieceNode = this.createPieceNode(pieceInfo);
                callFun && callFun(pieceInfo, pieceNode);
                pieceList[i][j] = [pieceNode, pieceInfo];
            }
        }
        if (this.isTestShow) {
            //显示完整的=>用于测试
            let testNode = new cc.Node(`testNode`);
            this.node.addChild(testNode);
            testNode.addComponent(cc.Sprite).spriteFrame = this.contentSf;
            testNode.setContentSize(this.bgSize);
            testNode.setAnchorPoint(cc.v2(0, 1));
            testNode.opacity = 50;
        }
        return pieceList;
    }

    /**
     * 根据行列获取对应的信息
     * @param row 行
     * @param col 列
     */
    private getPieceInfo(row: number, col: number) {
        let pieceInfo = { row: row, col: col } as I_PieceInfo;
        //计算类型
        let gradWidth = this.gradCell.width;
        let gradHeight = this.gradCell.height;
        let isLeftUp = (row == 0 && col == 0);
        let isRightUp = (row == 0 && col == gradWidth - 1);
        let isLeftDown = (col == 0 && row == gradHeight - 1);
        let isRightDown = (col == gradWidth - 1 && row == gradHeight - 1);
        let isLeft = (row < gradHeight - 1 && col == 0);
        let isUp = (col < gradWidth - 1 && row == 0);
        let isRight = (col == gradWidth - 1 && !isRightUp && !isRightDown);
        let isDown = (row == gradHeight - 1 && !isLeftDown && !isRightDown);
        let rowIsModeA = row % 2 != 0; //是否是奇数行
        let colIsModeA = col % 2 != 0; //是否是偶数行

        let pieceType: E_PiecePosType, offset = cc.v3(0, 0), startPos = cc.v3(0, 0);
        let scaleRatio = this.contentScalingRatio;
        let startX = this.pieceOriginaWidth * scaleRatio.x * col;
        let startY = this.pieceOriginaHeight * scaleRatio.y * row;
        let offsetX = (this.pieceOffset * 0 + 2 * this.blankOffset) * col;
        let offsetY = (this.pieceOffset * 0 + 2 * this.blankOffset) * row;
        //4个角
        if (isLeftUp) {
            pieceType = E_PiecePosType.left_up;
            offset = cc.v3(0, 0, 0);
            startPos = cc.v3(0, 0, 0);
        } else if (isLeftDown) {
            pieceType = E_PiecePosType.left_down;
            offset = cc.v3(0, offsetY);
            startPos = cc.v3(0, -startY);
        } else if (isRightUp) {
            pieceType = E_PiecePosType.right_up;
            offset = cc.v3(-offsetX, 0);
            startPos = cc.v3(startX, 0);
        } else if (isRightDown) {
            pieceType = E_PiecePosType.right_down;
            offset = cc.v3(-offsetX, offsetY);
            startPos = cc.v3(startX, -startY);
        } else {
            //四方向
            if (isRight) {
                pieceType = rowIsModeA ? E_PiecePosType.rightA : E_PiecePosType.rightB;
                offset = cc.v3(-offsetX, offsetY);
                startPos = cc.v3(startX, -startY);
            } else if (isLeft) {
                pieceType = rowIsModeA ? E_PiecePosType.leftA : E_PiecePosType.leftB;
                offset = cc.v3(0, offsetY);
                startPos = cc.v3(0, -startY);
            } else if (isUp) {
                pieceType = colIsModeA ? E_PiecePosType.upA : E_PiecePosType.upB;
                offset = cc.v3(-offsetX, 0);
                startPos = cc.v3(startX, 0);
            } else if (isDown) {
                pieceType = colIsModeA ? E_PiecePosType.downA : E_PiecePosType.downB;
                offset = cc.v3(-offsetX, offsetY);
                startPos = cc.v3(startX, -startY);
            } else {
                //中间
                if (colIsModeA && !rowIsModeA) {
                    pieceType = E_PiecePosType.centerA;
                    offset = cc.v3(-offsetX, this.pieceOffset * 2 * (row - 1));
                    startPos = cc.v3(startX, -this.pieceOriginaHeight * scaleRatio.y * (row - 1));
                } else if (!colIsModeA && rowIsModeA) {
                    pieceType = E_PiecePosType.centerA;
                    offset = cc.v3(-offsetX, this.pieceOffset * 2 * (row + 1));
                    startPos = cc.v3(startX, -this.pieceOriginaHeight * scaleRatio.y * (row + 1));
                } else if (colIsModeA && rowIsModeA) {
                    pieceType = E_PiecePosType.centerB;
                    offset = cc.v3(-offsetX, this.pieceOffset * 2 * (row + 1));
                    startPos = cc.v3(startX, -this.pieceOriginaHeight * scaleRatio.y * (row + 1));
                } else {
                    pieceType = E_PiecePosType.centerB;
                    offset = cc.v3(-offsetX, this.pieceOffset * 2 * (row - 1));
                    startPos = cc.v3(startX, -this.pieceOriginaHeight * scaleRatio.y * (row - 1));
                }
            }
        }
        // offset = cc.v3(0, 0, 0);

        pieceInfo.posType = pieceType;
        pieceInfo.maskSf = this.getPieceMaskSf(pieceType);
        pieceInfo.maskOffset = offset;
        pieceInfo.maskStartPos = startPos.sub(cc.v3(this.pieceOffset * 2, -this.pieceOffset * 2));
        pieceInfo.maskSfSize =
            cc.size(this.pieceOriginaWidth, this.pieceOriginaHeight);
        pieceInfo.contentSf = this.contentSf;
        pieceInfo.contentSfSize = this.bgSize;

        return pieceInfo;
    }

    /**
     * 创建一个碎片节点
     * @param info 创建碎片的Info
     */
    private createPieceNode(info: I_PieceInfo) {
        let pieceNode = new cc.Node(`piece`);
        pieceNode.setAnchorPoint(cc.v2(0, 1));
        pieceNode.setPosition(info.maskStartPos.add(info.maskOffset));
        pieceNode.setContentSize(info.maskSfSize);

        //添加碎片mask
        let mask = pieceNode.addComponent(cc.Mask);
        mask.type = cc.Mask.Type.IMAGE_STENCIL;
        mask.spriteFrame = info.maskSf;
        mask.alphaThreshold = 0.1;

        //设置内容节点位置
        let spNode = new cc.Node(`spNode`);
        spNode.setAnchorPoint(cc.v2(0, 1));
        spNode.setPosition(cc.v3(0, 0, 0).sub(pieceNode.position));
        spNode.setContentSize(info.contentSfSize);

        //mask节点下添加内容节点图片
        let contentSp = spNode.addComponent(cc.Sprite);
        contentSp.spriteFrame = info.contentSf;
        pieceNode.addChild(spNode);

        return pieceNode;
    }

    /**
     * 根据类型获取图片spriteFrame
     * @param type 要获取的类型
     */
    private getPieceMaskSf(type: E_PiecePosType) {
        // cc.log(`获取图片类型：${type}`);
        switch (type) {
            case E_PiecePosType.centerA: return this.pieceList.center.a;
            case E_PiecePosType.centerB: return this.pieceList.center.b;
            case E_PiecePosType.downA: return this.pieceList.down.a;
            case E_PiecePosType.downB: return this.pieceList.down.b;
            case E_PiecePosType.upA: return this.pieceList.up.a;
            case E_PiecePosType.upB: return this.pieceList.up.b;
            case E_PiecePosType.leftA: return this.pieceList.left.a;
            case E_PiecePosType.leftB: return this.pieceList.left.b;
            case E_PiecePosType.rightA: return this.pieceList.right.a;
            case E_PiecePosType.rightB: return this.pieceList.right.b;
            case E_PiecePosType.left_up: return this.pieceList.left_up;
            case E_PiecePosType.left_down: return this.pieceList.left_down;
            case E_PiecePosType.right_down: return this.pieceList.right_down;
            case E_PiecePosType.right_up: return this.pieceList.right_up;
            default: cc.warn(`没有类型：${type}的碎片`);
        }
    }

}
